using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace PKGames.SceneManagement
{
	public class TransitionController : MonoBehaviour
	{
		[Serializable]
		public class TransitionBackground
		{
			[Serializable]
			public class TransitionBackgroundData
			{
				[SerializeField]
				private string _scene;

				[SerializeField]
				private Sprite _backgroundSprite;

				public string Scene => _scene;

				public Sprite BackgroundSprite => _backgroundSprite;
			}

			[SerializeField]
			private List<TransitionBackgroundData> _data;

			public TransitionBackgroundData this[string scene] => _data.Find((TransitionBackgroundData d) => d.Scene == scene);

			public bool Contains(string scene)
			{
				return _data.Find((TransitionBackgroundData d) => d.Scene == scene) != null;
			}
		}

		private enum State
		{
			Idle,
			FadeIn,
			TransitionOn,
			FadeOut
		}

		public static bool SkipFadeout;

		[SerializeField]
		private Image _transitionImage;

		[SerializeField]
		private Canvas _canvas;

		[SerializeField]
		private TransitionBackground _background;

		private State _currentState;

		private Func<IEnumerator> _onFadeInFinished;

		private Func<IEnumerator> _onFadeOutFinished;

		private const float FadeTime = 0.15f;

		public IEnumerator FadeIn(Func<IEnumerator> onFinish, string scene)
		{
			_canvas.gameObject.SetActive(value: true);
			if (_background.Contains(scene))
			{
				_transitionImage.sprite = _background[scene].BackgroundSprite;
			}
			_onFadeInFinished = onFinish;
			yield return TryChangeToNextState(State.FadeIn);
		}

		public IEnumerator FadeOut(Func<IEnumerator> onFinish)
		{
			_onFadeOutFinished = onFinish;
			yield return TryChangeToNextState(State.FadeOut);
		}

		private IEnumerator TryChangeToNextState(State nextState)
		{
			if (CanChangeToNextState(nextState))
			{
				yield return ChangeToNextState(nextState);
			}
		}

		private bool CanChangeToNextState(State nextState)
		{
			switch (_currentState)
			{
			case State.Idle:
				return nextState == State.FadeIn;
			case State.FadeIn:
				return nextState == State.FadeOut;
			case State.FadeOut:
				return nextState == State.Idle;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		private IEnumerator ChangeToNextState(State nextState)
		{
			_currentState = nextState;
			switch (_currentState)
			{
			case State.TransitionOn:
				break;
			case State.Idle:
				yield return SetIdleState();
				break;
			case State.FadeIn:
				yield return SetFadeInState();
				break;
			case State.FadeOut:
				yield return SetFadeOutState();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		private IEnumerator SetIdleState()
		{
			if (SkipFadeout)
			{
				SkipFadeout = false;
			}
			else
			{
				_canvas.gameObject.SetActive(value: false);
				_transitionImage.color = new Color(1f, 1f, 1f, 0f);
			}
			yield return null;
		}

		private IEnumerator SetFadeInState()
		{
			_canvas.enabled = true;
			yield return FadeInTransition();
		}

		private IEnumerator FadeInTransition()
		{
			Image transitionImage = _transitionImage;
			Color color = _transitionImage.color;
			yield return FadeImage(transitionImage, color.a, 1f, 0.15f, OnFadeInEnd);
		}

		private IEnumerator OnFadeInEnd()
		{
			yield return TryChangeToNextState(State.TransitionOn);
			yield return _onFadeInFinished.Fire();
		}

		private IEnumerator FadeImage(Graphic image, float startAlpha, float endAlpha, float fadeTime, Func<IEnumerator> onFinish)
		{
			AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, startAlpha, fadeTime, endAlpha);
			for (float time = 0f; time < fadeTime; time += Time.deltaTime)
			{
				image.color = new Color(1f, 1f, 1f, animationCurve.Evaluate(time));
				yield return null;
			}
			image.color = Color.white;
			yield return onFinish.Fire();
		}

		private IEnumerator SetFadeOutState()
		{
			yield return FadeOutAnimation();
		}

		private IEnumerator FadeOutAnimation()
		{
			if (SkipFadeout)
			{
				yield return OnFadeOutEnd();
			}
			else
			{
				yield return FadeImage(_transitionImage, 1f, 0f, 0.15f, OnFadeOutEnd);
			}
		}

		private IEnumerator OnFadeOutEnd()
		{
			yield return TryChangeToNextState(State.Idle);
			yield return _onFadeOutFinished.Fire();
		}
	}
}
